package scoreCard.LivestockJudging3C;

import java.util.ArrayList;
import java.util.List;

public class ScoringCalculator {
    private List<Integer> officialOrder;
    private List<Integer> officialCuts;
    private List<Integer> personalOrder;

    /**
     * Public constructor with no arguments. Sets official order to {1,2,3,4}.
     * Sets officialCuts to {1,1,1}. Sets personalOrder to {1,2,3,4}
     */
    public ScoringCalculator() {
	int[] offOrder = { 1, 2, 3, 4 };
	int[] offCuts = { 1, 1, 1 };
	int[] persOrder = { 1, 2, 3, 4 };

	this.officialOrder = intToList(offOrder);
	this.officialCuts = intToList(offCuts);
	this.personalOrder = intToList(persOrder);
    }

    /**
     * Public constructor for calculator object. takes in three arrays of
     * Integers representing the official class score, cut for the class, and
     * the users own personal score.
     */
    public ScoringCalculator(int[] officialOrder, int[] officialCuts,
	    int[] personalOrder) {
	this.officialOrder = intToList(officialOrder);
	this.officialCuts = intToList(officialCuts);
	this.personalOrder = intToList(personalOrder);

	validateOrder(this.officialOrder);
	validateCuts(this.officialCuts);
	validateOrder(this.personalOrder);

    }

    /**
     * converts an array of primitive int objects into a list of Integer
     * objects.
     * 
     */
    public List<Integer> intToList(int[] intArr) {
	List<Integer> intList = new ArrayList<Integer>();

	for (int val : intArr) {
	    Integer tmpInt = val;
	    intList.add(tmpInt);
	}

	return intList;
    }

    /**
     * Public constructor for calculator object. takes in three lists of
     * Integers representing the official class score, cut for the class, and
     * the users own personal score.
     */
    public ScoringCalculator(List<Integer> officialOrder,
	    List<Integer> officialCuts, List<Integer> personalOrder) {

	this.setOfficialOrder(officialOrder);
	this.setOfficialCuts(officialCuts);
	this.setPersonalOrder(personalOrder);

    }

    public final List<Integer> getOfficialOrder() {
	return new ArrayList<Integer>(officialOrder);
    }

    public final List<Integer> getOfficialCuts() {
	return new ArrayList<Integer>(officialCuts);
    }

    public final List<Integer> getPersonalOrder() {
	return new ArrayList<Integer>(personalOrder);
    }

    public final void setOfficialOrder(List<Integer> newOrder) {

	validateOrder(newOrder);

	this.officialOrder = new ArrayList<Integer>(newOrder);
    }

    public final void setPersonalOrder(List<Integer> newOrder) {
	validateOrder(newOrder);

	this.personalOrder = new ArrayList<Integer>(newOrder);
    }

    public final void setOfficialCuts(List<Integer> newCuts) {
	validateCuts(newCuts);

	this.officialCuts = new ArrayList<Integer>(newCuts);
    }

    public void validateOrder(List<Integer> order) throws RuntimeException {
	final int NO_ANIMALS = 4;

	if (order.size() != NO_ANIMALS) {
	    throw new RuntimeException(
		    "Error! An ordering must contain exactly " + NO_ANIMALS
			    + " animals");
	}

	for (Integer i = 1; i <= NO_ANIMALS; i++) {
	    if (!order.contains(i)) {
		throw new RuntimeException("Error! The number " + i
			+ " was duplicated in an ordering");
	    }
	}
    }

    private void validateCuts(List<Integer> cuts) throws RuntimeException {
	final int NO_CUTS = 3;
	// the total of the three cuts cannot exceed 15
	final int TOTAL_CUT_MAX = 15;
	// if the cuts total 15, the middle pair cannot exceed 5
	final int MID_PAIR_MAX_15 = 5;
	// if the cuts total 14, the middle pair cannot exceed 8
	final int MID_PAIR_MAX_14 = 8;

	if (cuts.size() != NO_CUTS) {
	    throw new RuntimeException(
		    "Error! An ordering must contain exactly " + NO_CUTS
			    + " cuts");
	}

	int total = 0;
	for (int i = 0; i < cuts.size(); i++) {
	    total += cuts.get(i);
	}

	if (total > TOTAL_CUT_MAX) {
	    throw new RuntimeException(
		    "Error! The total of the three penalties cannot exceed 15 points.");
	} else if (total == TOTAL_CUT_MAX) {
	    if (cuts.get(1) > MID_PAIR_MAX_15) {
		throw new RuntimeException(
			"Error! If the total of the three penalties is 15 points, the middle cut cannot be more than 5 points.");
	    }
	} else if (total == TOTAL_CUT_MAX - 1) {
	    if (cuts.get(1) > MID_PAIR_MAX_14) {
		throw new RuntimeException(
			"Error! If the total of the three penalties is 14 points, the middle cut cannot be more than 8 points.");
	    }
	}
    }

    public final int calculateScore() {
	final int INITIAL_SCORE = 50;

	int score = INITIAL_SCORE;

	for (int i = 0; i < officialOrder.size() - 1; i++) {
	    for (int j = i + 1; j < officialOrder.size(); j++) {
		// identify animals at positions i and j
		int p1 = officialOrder.get(i);
		int p2 = officialOrder.get(j);

		// get official pairing of animals
		int offDiff = officialOrder.indexOf(p2)
			- officialOrder.indexOf(p1);

		// the personal ordering is correct if it matches that of the
		// official ordering,
		Boolean correct = (personalOrder.indexOf(p2) - personalOrder
			.indexOf(p1)) > 0;

		if (!correct) {
		    int cutTotal = 0;
		    for (int cutIndex = 0; cutIndex < offDiff; cutIndex++) {
			int cut = officialCuts.get(i + cutIndex);
			cutTotal += cut;
		    }
		    score -= cutTotal;

		    // TODO code to output specific details on deductions
		    // System.out.printf(
		    // "You incorrectly placed %d over %d:  -%d points\n",
		    // p2, p1, cutTotal);
		} else {
		    // System.out.printf(
		    // "  You correctly placed %d over %d:  %d points\n",
		    // p1, p2, 0);
		}
	    }
	}
	return score;
    }
}
